﻿using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace DevExpress.CrmDemo.Win.Helpers
{

    public struct IconInfo
    {
        public bool fIcon;
        public int xHotspot;
        public int yHotspot;
        public IntPtr hbmMask;
        public IntPtr hbmColor;
    }

    /// <summary>
    /// Wraps a custom cursor created from a bitmap.  Disposable to clean up unmanaged resource.
    /// </summary>
    public class CustomCursorWrapper : IDisposable
    {
        #region Private constructor
        private CustomCursorWrapper(IntPtr cursorPointer)
        {
            this.CursorPointer = cursorPointer;
            this.Cursor = new Cursor(cursorPointer);
        }
        #endregion

        #region Public members
        public Cursor Cursor { get; private set; }

        public static CustomCursorWrapper CreateFromBitmap(Bitmap bitmap, Point point)
        {
            if (bitmap != null)
            {
                Graphics canvas = Graphics.FromImage(bitmap);
                canvas.Save();

                IconInfo iconInfo = new IconInfo();
                IntPtr pointer = bitmap.GetHicon();
                GetIconInfo(pointer, ref iconInfo);
                var cursorPointer = CreateIconIndirect(ref iconInfo);

                // Clean up intermediary unmanaged resources
                //
                if (iconInfo.hbmColor != IntPtr.Zero)
                {
                    DeleteObject(iconInfo.hbmColor);
                }
                if (iconInfo.hbmMask != IntPtr.Zero)
                {
                    DeleteObject(iconInfo.hbmMask);
                }
                return new CustomCursorWrapper(cursorPointer);
            }
            return null;
        }

        private static Bitmap ArrowCursorImage
        {
            get
            {
                if (_arrowCursorImage == null)
                {
                    Assembly myAssembly = Assembly.GetExecutingAssembly();
                    using (Stream stream = myAssembly.GetManifestResourceStream(typeof(CustomCursorWrapper).Namespace +  ".base_cursor.png"))
                    {
                        _arrowCursorImage = new Bitmap(stream);
                    }
                }
                return _arrowCursorImage;
            }
        }
        private static Bitmap _arrowCursorImage = null;
        #endregion

        #region PInvoke methods
        [DllImport("user32.dll")]
        public static extern IntPtr CreateIconIndirect(ref IconInfo icon);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

        [DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr handle);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public extern static bool DestroyIcon(IntPtr handle);

        private IntPtr CursorPointer { get; set; }
        #endregion

        #region IDisposable implementation
        private bool disposed = false;

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                if (CursorPointer != IntPtr.Zero)
                {
                    DestroyIcon(CursorPointer);
                    CursorPointer = IntPtr.Zero;
                    this.Cursor = null;
                }
                disposed = true;
            }
        }

        ~CustomCursorWrapper()
        {
            Dispose(false);
        }
        #endregion
    }
}
